#pragma once

#include "Connection.hpp"
#include "Epoller.hpp"
#include "Socket.hpp"
#include"Util.hpp"
#include"Channel.hpp"
#include"Reactor.hpp"

class Listener : public Connection
{
public:
    Listener(uint16_t port)
        : _listensockfd(std::make_shared<TcpSocket>()), _port(port)
    {
        // 创建监听套接字
        _listensockfd->BuildListenSocket(_port);
        // 需要将监听套接字放到Reactor 的哈希表中并设置到epoll内核中
        SetSockfd(_listensockfd->Sockfd());
        SetEvents(EPOLLIN | EPOLLET); // 设置为ET模式
    }
    ~Listener() {}

    void Recver() override
    {
        while (true)
        {
            // 对于监听套接字来说读取数据就是获取连接
            InetAddr clientaddr;
            int error = 0;
            int sockfd = _listensockfd->Accept(&clientaddr, &error);
            if (sockfd < 0)
            {
                // 根据error 判断究竟是非阻塞没有连接的原因还是错误
                if(error == EAGAIN)
                {
                    //获取连接完毕了
                    break;
                }
                else if(error == EINTR)
                {
                    //信号中断
                    continue;
                }
                else{
                    break;//真正的错误
                }
            }
            //走到此处就是sockfd 合法，需要将连接添加进_connections中
            SetNonBlock(sockfd);//将文件描述符设置为非阻塞
            std::shared_ptr<Connection> conn = std::make_shared<Channel>(sockfd , clientaddr);

            //listensockfd 将回调函数传递给接收到的连接
            SetCB(_cb);

            //将conn 放入Reactor 中的哈希表中
            Owner()->AddConnection(conn);
        }
    }
    void Sender() override
    {
        //不用实现
    }
    void Excepter() override
    {
        //不用实现
    }

private:
    // 监听套接字
    std::shared_ptr<Socket> _listensockfd;
    uint16_t _port;
};